#!/usr/bin/env python
#-*- coding: UTF-8 -*-
# schapi.py: Programming interface of task manager for scheduler
#
# Copyright (C) 2008-2010 Hily Jiang <hilyjiang@gmail.com>
#
# This file is part of dtask.
#
# This software is provided 'as-is', without any express or implied
# warranty.  In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
#    claim that you wrote the original software. If you use this software
#    in a product, an acknowledgment in the product documentation would be
#    appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
#    misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.

"""
Programming interface of task manager for scheduler.
"""

import threading
import socket
import select

from utils import CommandBuffer


CFG_SCH_BUFSIZ = 1024


class TaskContainer(object):
    """Task container, containing task info and task result."""
    def __init__(self):
        self.taskInfo = None
        self.taskEvent = threading.Event()
        self.connected = False
        self.closed = False

    def connect(self, taskServerIP, taskServerPort, schName='', schKey=''):
        if self.connected: return False
        self.connected = True

        self.schName = schName
        self.schKey = schKey

        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        addr = (taskServerIP, taskServerPort)
        try:
            self.sock.connect(addr)
        except:
            print 'connect failed', addr
            self.connected = False
            return False

        # if schName exists send schName and schKey to server
        if self.schName != '':
            self.sock.sendall('PASSPORT %s %s\n' % (self.schName, self.schKey))

        self.rBuf = CommandBuffer()
        self.recvThread = threading.Thread(target=self.__recvThreadFunc)
        self.recvThread.setDaemon(True)
        self.recvThread.start()
        return True

    def close(self):
        """Close connection to task manager."""
        if not self.connected: return False
        self.closed = True
        self.connected = False

    def __recvThreadFunc(self):
        """Thread function to receive data."""
        while True:
            infds, outfds, errfds = select.select([self.sock,], [], [], 5)
            if infds and len(infds) == 0: # timeout
                if self.closed == True:
                    self.taskInfo = None
                    self.taskEvent.set()
                    break
                else:
                    continue
            data = self.sock.recv(CFG_SCH_BUFSIZ)
            if data == '':
                self.taskInfo = None
                self.taskEvent.set()
                break
            self.rBuf.addData(data)
            cmdInfo = self.rBuf.getCommand()
            if cmdInfo:
                cmd, params = cmdInfo
                if cmd == 'TASK':
                    try:
                        taskId, taskType, taskParams = params.split(None, 2)
                        self.taskInfo = (taskId, taskType, taskParams)
                    except Exception:
                        self.taskInfo = None
                    self.taskEvent.set()

    def getTask(self):
        """Get a task from task manager.

        Return None if error occur.
        """
        self.sock.send('GETTASK\n')
        self.taskEvent.wait()
        self.taskEvent.clear()
        return self.taskInfo

    def writeResult(self, taskId, result):
        """Write task result to task manager."""
        self.sock.sendall('RESULT %s %s\n' % (taskId, result))

    def updateStatus(self, taskId, status):
        """Update status of the task."""
        self.sock.sendall('STATUS %s %s\n' % (taskId, status))


def test():
    tc = TaskContainer()
    if not tc.connect('127.0.0.1', 7709, 'testsch'):
        print 'connect failed'
    else:
        taskInfo = tc.getTask()
        if taskInfo == None:
            print 'get task error'
        else:
            taskId, taskType, taskParams = taskInfo
            print 'task id:    ', taskId
            print 'task type:  ', taskType
            print 'task params:', taskParams

            tc.updateStatus(taskId, 'nodm 127.0.0.1 8809 1229435623 0')
            tc.updateStatus(taskId, 'nod testnod 127.0.0.1 8810 1229435890 0')


if __name__ == '__main__':
    test()
